package store

import (
	"fmt"
	"fyne.io/fyne/v2/data/binding"
	"image/color"
	"log"
	"ping-info-go/pkg/global"
	"sync"
	"time"
)

var (
	PingStatus = pingStatus{
		Started:      false,
		Paused:       true,
		pingRound:    0,
		ContinueChan: make(chan bool, 1),
		PauseChan:    make(chan bool, 1),
		FinishChan:   make(chan bool, 1),
		mu:           sync.Mutex{},
	}

	MiddleInfoStr  = ""
	MiddleInfoBind = binding.BindString(&MiddleInfoStr)
	TimePingNext   = time.Now()
)

type pingStatus struct {
	Started      bool
	Paused       bool
	pingRound    uint64 // ping 轮数
	ContinueChan chan bool
	PauseChan    chan bool
	StopChan     chan bool
	FinishChan   chan bool
	NextTickChan <-chan time.Time
	mu           sync.Mutex
}

type TableData struct {
	// 每次测试的结果
	Name       string        // 备注的名称
	Host       string        // 主机名
	IP         string        // 主机名解析的IP地址
	Delay      time.Duration // 最近一次的延迟
	Status     string        // 最近一次的状态
	RangeTimes int64         // 当前测试轮第几次

	// 统计测试的结果
	TotalNum   int64         // 总次数
	SuccessNum int64         // 成功次数
	FailNum    int64         // 失败次数
	AvgDelay   time.Duration // 平均延迟
	MinDelay   time.Duration // 最小延迟
	MaxDelay   time.Duration // 最大延迟

	// 写锁
	Mu *sync.Mutex
}

type PingResult struct {
	IP    string
	Delay time.Duration
	Error error
}

func (t *TableData) GetShowColor() color.Color {
	if t.FailNum != 0 && t.FailNum == t.TotalNum {
		return color.RGBA{R: 255, G: 200, B: 200, A: 255}
	}
	if t.FailNum != 0 && t.FailNum != t.TotalNum {
		return color.RGBA{R: 255, G: 255, B: 200, A: 255}
	}
	//if t.FailNum == 0 {
	//	return color.RGBA{R: 200, G: 255, B: 200, A: 255}
	//}
	return color.Transparent
}

func (t *TableData) GetShowColorHex() string {
	r, g, b, a := t.GetShowColor().RGBA()
	// RGBA 返回 0-65535，需要压缩到 0-255
	if a == 0 {
		return "#FFFFFF" // 透明时默认白色
	}
	return fmt.Sprintf("#%02X%02X%02X", uint8(r>>8), uint8(g>>8), uint8(b>>8))
}

// GetShowStr 根据 global.HeaderConf 配置的列字段顺序读取
func (t *TableData) GetShowStr(idx int) string {
	switch idx {
	case 0:
		return t.Name
	case 1:
		return t.Host
	case 2:
		return t.IP
	case 3:
		return fmt.Sprintf("%d", t.SuccessNum)
	case 4:
		return fmt.Sprintf("%d", t.FailNum)
	case 5:
		if t.TotalNum == 0 {
			return "N/A"
		}
		lossPercent := float64(t.FailNum) * 100.0 / float64(t.TotalNum)
		return fmt.Sprintf("%.2f%%", lossPercent)
	case 6:
		return t.Status
	case 7:
		return fmt.Sprintf("%v", t.Delay)
	case 8:
		return fmt.Sprintf("%v", t.AvgDelay)
	case 9:
		return fmt.Sprintf("%v", t.MaxDelay)
	case 10:
		return fmt.Sprintf("%v", t.MinDelay)
	default:
		return "N/A"
	}
}

var TableDataList = make([]*TableData, 0)

func (p *pingStatus) Restart() {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.Started {
		go func() {
			log.Println("Start StopChan 写入 true 1")
			p.StopChan <- true
			log.Println("Start StopChan 写入 true 2")
		}()
	} else {
		// 第一次启动需要写入FinishChan
		go func() {
			p.FinishChan <- true
		}()
	}

	p.Started = true
	log.Println("Start Restart done")
}

func (p *pingStatus) ReversalPing() {
	p.mu.Lock()
	defer p.mu.Unlock()

	if !p.Started {
		return
	}

	p.Paused = !p.Paused

	p.PauseChan <- true

	//if p.Paused {
	//	p.doContinue()
	//	return
	//}
	//
	//p.doPause()
}

func (p *pingStatus) DoFinish() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.FinishChan <- true
	p.Paused = true
}

func (p *pingStatus) doPause() {
	p.Paused = true
	//close(p.PauseChan)
	log.Println("ping 已停止")
	//go p.setNextTickContinue()
}

func (p *pingStatus) doContinue() {
	p.Paused = false
	//close(p.ContinueChan)
	log.Println("ping 已继续")
	//go PingStatus.ContinuePing()
	return
}

func (p *pingStatus) ContinuePing() {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.Paused = false
	//p.ContinueChan = make(chan bool, 1)
	//p.PauseChan = make(chan bool, 1)
}

func (p *pingStatus) setNextTickContinue() {
	now := time.Now()
	TimePingNext = now.Add(global.PingInterval)
	p.NextTickChan = time.Tick(TimePingNext.Sub(now))
	select {
	case <-p.ContinueChan:
		return
	case <-p.NextTickChan:
		p.ReversalPing()
	}
}

func (p *pingStatus) SetNextTickContinue(thisPingRound uint64, nextFun func(continuePing bool)) {
	now := time.Now()
	TimePingNext = now.Add(global.PingInterval)
	<-time.Tick(TimePingNext.Sub(now))
	if thisPingRound == p.GetPingRound() {
		nextFun(false)
	}
}

func (p *pingStatus) AddPingRound() uint64 {
	p.mu.Lock()
	defer p.mu.Unlock()
	p.pingRound++
	return p.pingRound
}

func (p *pingStatus) GetPingRound() uint64 {
	p.mu.Lock()
	defer p.mu.Unlock()
	return p.pingRound
}
